#include "cairo.h"
#include "cairo-ft.h"
#include <ft2build.h>
#include <stdlib.h>
#include FT_SFNT_NAMES_H
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_BBOX_H
#include FT_TYPE1_TABLES_H

#include "Log.h"

#define SIZE    (50)
#define CX  ((SIZE / 2))
#define CY  ((SIZE / 2))
#define R   ((SIZE / 2) - 2)

#define M_PI	3.141596

/* 把角度转换为所对应的弧度 */
#define ANGLE(ang)  (ang * 3.1415926 / 180.0)

#define HEIGHT		500
#define WIDTH		800
#define FONTSIZE	30

#include <time.h>
#include <stdint.h>

typedef struct {
	int left;
	int top;
	int width;
	int height;
} SPosition;

/*
// 实现斜体

cairo_matrix_t matrix;
cairo_matrix_init(&matrix, 1, 0,
				-0.25, 1,
				0, 0);
cairo_matrix_scale(&matrix, FONTSIZE, FONTSIZE);
cairo_set_font_matrix(c, &matrix);
*/

/*
cairo_text_extents_t es;
cairo_scaled_font_glyph_extents(sface, glyphs, glyph_count, &es);
printf("extents  h %.2f, w %.2f, xa %.2f, xb %.2f, y %.2f\n\n\n\n\n",
		es.height, es.width,
		es.x_advance,es.x_bearing,
		es.y_bearing);
*/

unsigned int get_proc_mem(unsigned int pid);

static void drawTextCore(cairo_t *c, cairo_font_face_t *ct, int fontSize, int slant, int bold) {
	cairo_save(c);

	cairo_set_font_face(c, ct);
	cairo_set_font_size(c, fontSize);

	cairo_scaled_font_t * sface = cairo_get_scaled_font(c);

	cairo_font_extents_t extents;
	cairo_scaled_font_extents(sface, &extents);
//	printf("extents  ascent: %f, descent: %f, height: %f, x_advance: %f, y_advance: %f\n",
//			extents.ascent,
//			extents.descent,
//			extents.height,
//			extents.max_x_advance,
//			extents.max_y_advance);

	if (slant) {
		// 斜体
		cairo_ft_scaled_font_set_synthesize(sface, CAIRO_FT_SYNTHESIZE_OBLIQUE);
	}

	if (bold) {
		// 粗体
		cairo_ft_scaled_font_set_synthesize(sface, CAIRO_FT_SYNTHESIZE_BOLD);
	}

	cairo_set_source_rgb(c, 0, 0, 1);
	cairo_rectangle(c, 0, 0, WIDTH, extents.height);
	cairo_stroke(c);

	cairo_translate(c, 0, extents.ascent);
	cairo_set_source_rgb(c, 0, 0, 1);

	const char* text = "郭";	// "郭a洁bg尛";
	cairo_glyph_t glyph;

	logBegin("show glyphs");

	const char *p = text;
	uint32_t unicode;
	int len = 0;
	double x = 0, y = 0;

	while (*p) {
		len = cairo_scaled_font_get_one_glyph(sface, p, &glyph);
		if (len == -1) {
			break;
		}

		glyph.x = x;
		cairo_show_glyphs(c, &glyph, 1);

		cairo_text_extents_t es;
		cairo_scaled_font_glyph_extents(sface, &glyph, 1, &es);

		x += es.x_advance;
		p += len;
	}

	logEnd("show glyphs");

	cairo_ft_scaled_font_unset_synthesize(sface, CAIRO_FT_SYNTHESIZE_OBLIQUE);
	cairo_ft_scaled_font_unset_synthesize(sface, CAIRO_FT_SYNTHESIZE_BOLD);

	cairo_restore(c);
}

static void drawTextCoreEx(cairo_t *c, cairo_font_face_t *ct, int fontSize, int slant, int bold, SPosition *pPos) {
	cairo_save(c);

	cairo_translate(c, pPos->left, pPos->top);

	cairo_set_font_face(c, ct);
	cairo_set_font_size(c, fontSize);

	cairo_scaled_font_t * sface = cairo_get_scaled_font(c);

	cairo_font_extents_t extents;
	cairo_scaled_font_extents(sface, &extents);

	if (slant) {	// 斜体
		cairo_ft_scaled_font_set_synthesize(sface, CAIRO_FT_SYNTHESIZE_OBLIQUE);
	}

	if (bold) {		// 粗体
		cairo_ft_scaled_font_set_synthesize(sface, CAIRO_FT_SYNTHESIZE_BOLD);
	}

	cairo_set_source_rgb(c, 0, 0, 1);
	cairo_rectangle(c, 0, 0, pPos->width, pPos->height);
	cairo_stroke(c);

	cairo_translate(c, 0, extents.ascent);
	cairo_set_source_rgb(c, 0, 0, 1);

	const char* text = "郭郭\na洁bgh值得要收郭郭\na洁bgh值得要收郭郭\na洁bgh值得要收";	// "郭a洁bg尛";
	cairo_glyph_t glyph;

	logBegin("show glyphs");

	const char *p = text;
	uint32_t unicode;
	int len = 0;
	double x = 0, y = 0;

	while (*p) {
		len = cairo_scaled_font_get_one_glyph(sface, p, &glyph);
		if (len == -1) {
			break;
		}

		cairo_text_extents_t es;
		cairo_scaled_font_glyph_extents(sface, &glyph, 1, &es);

		if (*p == '\n') {
			p += len;
			x = 0;
			y += extents.height;
			continue;
		}

		if ((p != text) && (x + es.x_advance > pPos->width)) {
			x = 0;
			y += extents.height;
		}

		glyph.x = x;
		glyph.y = y;
		cairo_show_glyphs(c, &glyph, 1);

		p += len;
		x += es.x_advance;
	}

	logEnd("show glyphs");

	cairo_ft_scaled_font_unset_synthesize(sface, CAIRO_FT_SYNTHESIZE_OBLIQUE);
	cairo_ft_scaled_font_unset_synthesize(sface, CAIRO_FT_SYNTHESIZE_BOLD);

	cairo_restore(c);
}

#if 0
static void drawTextCoreEx(cairo_t *c, cairo_scaled_font_t *sface, int fontSize, int slant, int bold) {
	cairo_save(c);

	cairo_set_scaled_font(c, sface);
	cairo_matrix_t matrix;
	cairo_matrix_init(&matrix, fontSize, 0, 0, fontSize, 0, 0);
	cairo_set_font_matrix(c, &matrix);		// 设置字体大小

	printf("fontSize %d\n", fontSize);

	cairo_font_extents_t extents;
	cairo_scaled_font_extents(sface, &extents);
	printf("extents  ascent: %f, descent: %f, height: %f, x_advance: %f, y_advance: %f\n",
			extents.ascent,
			extents.descent,
			extents.height,
			extents.max_x_advance,
			extents.max_y_advance);

	if (slant) {	// 斜体
		cairo_ft_scaled_font_set_synthesize(sface, CAIRO_FT_SYNTHESIZE_OBLIQUE);
	}

	if (bold) {		// 粗体
		cairo_ft_scaled_font_set_synthesize(sface, CAIRO_FT_SYNTHESIZE_BOLD);
	}

	cairo_set_source_rgb(c, 0, 0, 1);
	cairo_rectangle(c, 0, 0, WIDTH, extents.height);
	cairo_stroke(c);

	cairo_translate(c, 0, extents.ascent);
	cairo_set_source_rgb(c, 0, 0, 1);

	const char* text = "郭";	// "郭a洁bg尛";
	cairo_glyph_t glyph;

	logBegin("show glyphs");

	const char *p = text;
	uint32_t unicode;
	int len = 0;
	double x = 0, y = 0;

	while (*p) {
		len = cairo_scaled_font_get_one_glyph(sface, p, &glyph);
		if (len == -1) {
			break;
		}

		glyph.x = x;
		cairo_show_glyphs(c, &glyph, 1);

		cairo_text_extents_t es;
		cairo_scaled_font_glyph_extents(sface, &glyph, 1, &es);

		x += es.x_advance;
		p += len;
	}

	logEnd("show glyphs");

	cairo_ft_scaled_font_unset_synthesize(sface, CAIRO_FT_SYNTHESIZE_OBLIQUE);
	cairo_ft_scaled_font_unset_synthesize(sface, CAIRO_FT_SYNTHESIZE_BOLD);

	cairo_restore(c);
}
#endif

static void drawText(cairo_t *c) {
	FT_Library value;
	FT_Error status;
	FT_Face face;

	cairo_font_face_t * ct;

	const char *filename = "fzcircle.ttf";

	printf("1. mem %d\n", get_proc_mem(getpid()));
	status = FT_Init_FreeType(&value);
	if (status != 0) {
		fprintf(stderr, "Error %d opening library.\n", status);
		exit(EXIT_FAILURE);
	}
	status = FT_New_Face(value, filename, 0, &face);
	if (status != 0) {
		fprintf(stderr, "Error %d opening %s.\n", status, filename);
		exit(EXIT_FAILURE);
	}
	printf("2. mem %d\n", get_proc_mem(getpid()));

	ct = cairo_ft_font_face_create_for_ft_face(face, 0);

#if 0
	cairo_font_options_t *options = cairo_font_options_create();
	cairo_matrix_t identity;
	cairo_matrix_init_identity(&identity);
	cairo_scaled_font_t *sfont = cairo_scaled_font_create(ct, &identity, &identity, options);
	printf("sfont %p\n", sfont);
#endif

	int sm = get_proc_mem(getpid());
#if 0
	for (int i = 0; i < 1; ++i) {
//		cairo_translate(c, 0, 2 * FONTSIZE);
		drawTextCore(c, ct, ((i + 1) % 20) * FONTSIZE, 0, 0);
	}
#elif 0
	drawTextCore(c, ct, FONTSIZE, 0, 0);
#else
	SPosition pos = { 100, 50, 150, 100 };
	drawTextCoreEx(c, ct, FONTSIZE, 0, 0, &pos);
#endif
//	cairo_translate(c, 0, 2 * FONTSIZE);
//	cairo_set_font_size(c, 1.5 * FONTSIZE);
//	drawTextCore(c, ct, FONTSIZE, 1, 0);
//	printf("22222. mem %d\n", get_proc_mem(getpid()));
//	cairo_set_font_size(c, 1.5 * FONTSIZE);
//	cairo_translate(c, 0, 2 * FONTSIZE);
//	drawTextCore(c, ct, FONTSIZE, 0, 1);
//	printf("33333. mem %d\n", get_proc_mem(getpid()));
//	cairo_set_font_size(c, FONTSIZE);
//	cairo_translate(c, 0, 2 * FONTSIZE);
//	drawTextCore(c, ct, FONTSIZE, 0, 1);
//	printf("44444. mem %d\n", get_proc_mem(getpid()));

	printf("text take mem %d\n\n\n", get_proc_mem(getpid()) - sm);

//	cairo_scaled_font_destroy(sfont);
//	_cairo_scaled_font_map_destroy();
	cairo_font_face_destroy(ct);

	FT_Done_Face(face);
	FT_Done_FreeType(value);
}

static void drawShape(cairo_t *cr) {
	cairo_save(cr);
	cairo_set_source_rgb (cr, 0, 1, 0);
	cairo_set_line_width (cr, 2);

	cairo_move_to(cr, 50, 300);
	cairo_curve_to(cr, 180, 120, 200, 100, 220, 180);
	cairo_stroke(cr);

	cairo_rectangle (cr, 20, 20, 120, 80);
	cairo_rectangle (cr, 180, 20, 80, 80);
	cairo_stroke_preserve (cr);
	cairo_set_source_rgb (cr, 1, 1, 1);
	cairo_fill (cr);

	cairo_set_source_rgb (cr, 0, 0, 0);
	cairo_arc (cr, 330, 60, 40, 0, 2 * M_PI);
	cairo_stroke_preserve (cr);
	cairo_set_source_rgb (cr, 1, 1, 1);
	cairo_fill (cr);

	cairo_set_source_rgb (cr, 0, 0, 0);
	cairo_arc (cr, 90, 160, 40, M_PI / 4, M_PI);
	cairo_close_path (cr);
	cairo_stroke_preserve (cr);
	cairo_set_source_rgb (cr, 1, 1, 1);
	cairo_fill (cr);

	cairo_set_source_rgb (cr, 0, 0, 0);
	cairo_translate (cr, 220, 180);
	cairo_scale (cr, 1, 0.7);
	cairo_arc (cr, 0, 0, 50, 0, 2 * M_PI);
	cairo_stroke_preserve (cr);
	cairo_set_source_rgb (cr, 1, 1, 1);
	cairo_fill (cr);
	cairo_restore(cr);
}

static void drawPattern(cairo_t *cr) {
	cairo_save(cr);
	cairo_translate (cr, 50, 200);
	cairo_surface_t *image = cairo_image_surface_create_from_png("p.png");
    int w = cairo_image_surface_get_width(image);
    int h = cairo_image_surface_get_height(image);

    cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
    cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); // 重复

    cairo_matrix_t   matrix;
    cairo_matrix_init_scale(&matrix, w/256.0 * 5.0, h/256.0 * 5.0);
    cairo_pattern_set_matrix(pattern, &matrix);

    cairo_set_source(cr, pattern);

    cairo_rectangle(cr, 0, 0, 256.0, 256.0);
    cairo_fill(cr);

    cairo_pattern_destroy(pattern);
    cairo_surface_destroy(image);
    cairo_restore(cr);
}

static void drawGradient(cairo_t *cr) {
	cairo_save(cr);
	cairo_translate (cr, 320, 180);
	cairo_pattern_t *pat;

	pat = cairo_pattern_create_linear (0.0, 0.0,  0.0, 256.0);
	cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 0, 1);
	cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1);
	cairo_rectangle (cr, 0, 0, 256, 256);
	cairo_set_source (cr, pat);
	cairo_fill (cr);
	cairo_pattern_destroy (pat);

	pat = cairo_pattern_create_radial (115.2, 102.4, 25.6,
	                                   102.4,  102.4, 128.0);
	cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1);
	cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 0, 1);
	cairo_set_source (cr, pat);
	cairo_arc (cr, 128.0, 128.0, 76.8, 0, 2 * M_PI);
	cairo_fill (cr);
	cairo_pattern_destroy (pat);
	cairo_restore(cr);
}

static void drawByOperatorCore(cairo_t *cr, int x, int w, int h, cairo_operator_t op) {
	cairo_t *first_cr, *second_cr;
	cairo_surface_t *first, *second;

	first = cairo_surface_create_similar(cairo_get_target(cr),
			CAIRO_CONTENT_COLOR_ALPHA, w, h);

	second = cairo_surface_create_similar(cairo_get_target(cr),
			CAIRO_CONTENT_COLOR_ALPHA, w, h);

	first_cr = cairo_create(first);
	cairo_set_source_rgb(first_cr, 0, 0, 0.4);
	cairo_rectangle(first_cr, x, 20, 50, 50);
	cairo_fill(first_cr);

	second_cr = cairo_create(second);
	cairo_set_source_rgb(second_cr, 0.5, 0.5, 0);
	cairo_rectangle(second_cr, x + 10, 40, 50, 50);
	cairo_fill(second_cr);

	cairo_set_operator(first_cr, op);
	cairo_set_source_surface(first_cr, second, 0, 0);
	cairo_paint(first_cr);

	cairo_set_source_surface(cr, first, 0, 0);
	cairo_paint(cr);

	cairo_surface_destroy(first);
	cairo_surface_destroy(second);

	cairo_destroy(first_cr);
	cairo_destroy(second_cr);
}

static void drawByOperator(cairo_t *cr) {
	cairo_save(cr);
	cairo_operator_t oper[] = {
		CAIRO_OPERATOR_DEST_OVER,
		CAIRO_OPERATOR_DEST_IN,
		CAIRO_OPERATOR_OUT,
		CAIRO_OPERATOR_ADD,
		CAIRO_OPERATOR_ATOP,
		CAIRO_OPERATOR_DEST_ATOP,
	};

	for (int x = 20, y = 20, i = 0; i < 6; x += 80, i++) {
		drawByOperatorCore(cr, x, WIDTH, HEIGHT, oper[i]);
	}
	cairo_restore(cr);
}

int main(int argc, char *argv[]) {
	printf("1. mem %d\n", get_proc_mem(getpid()));

	cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
	cairo_t *cr = cairo_create(surface);

	printf("2. mem %d\n", get_proc_mem(getpid()));

	logBegin("fill rect");

	// 填充了背景色比透明情况下绘制时间短些
	cairo_set_source_rgba(cr, 1, 0, 1, 1);
	cairo_rectangle(cr, 0, 0, WIDTH, HEIGHT);
	cairo_fill(cr);

	logEnd("fill rect");

	int w, h;
	cairo_surface_t *image;
	image = cairo_image_surface_create_from_png(argv[1]);
	w = cairo_image_surface_get_width(image);
	h = cairo_image_surface_get_height(image);

	printf("3. mem %d\n", get_proc_mem(getpid()));

	logBegin("draw image");

	// 实现图片拉伸效果
#if 1
	cairo_surface_set_device_scale(image, 0.5, 1);
	cairo_surface_set_device_offset(image, 20, 20);
	cairo_set_source_surface(cr, image, 50, 200);
	cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);

	cairo_paint(cr);
	logEnd("draw image");
#else
	cairo_save(cr);
//	cairo_rectangle(cr, 150, 150, 100, 50);
//	cairo_clip(cr);
	cairo_translate(cr, 50, 100);
	cairo_scale(cr, 2.0f, 1);
//	cairo_surface_set_device_scale(image, 0.5f, 1);
	cairo_set_source_surface(cr, image, 0, 0);
	cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);
	printf("%s: 1. take time %d\n", __FUNCTION__, getCurrentTime() - startTime);
	startTime = getCurrentTime();
	cairo_paint(cr);
	printf("%s: 2. take time %d\n", __FUNCTION__, getCurrentTime() - startTime);
#endif
	cairo_surface_destroy(image);

//	image = cairo_image_surface_create_from_png ("block.png");
//	w = cairo_image_surface_get_width (image);
//	h = cairo_image_surface_get_height (image);
//// 105 106
//// 78 140 198 259 318   366
//	cairo_set_source_surface (cr, image, atoi(argv[1]), atoi(argv[2]));
//	cairo_paint (cr);
//	cairo_surface_destroy (image);

	printf("4. mem %d\n", get_proc_mem(getpid()));
//	cairo_save(cr);
//	cairo_rectangle(cr, 0, 0, 50, 150);
//	cairo_clip(cr);
	drawText(cr);
	printf("5. mem %d\n", get_proc_mem(getpid()));

#if 0
	drawShape(cr);
	drawPattern(cr);
	drawGradient(cr);
	drawByOperator(cr);
#endif

	cairo_destroy(cr);
	cairo_surface_write_to_png(surface, "arc.png");
	cairo_surface_destroy(surface);

	printf("6. mem %d\n", get_proc_mem(getpid()));

	return 0;
}
